package com.ailk.cuc.autotestbg.xml.business.impl.ecs;

import java.io.File;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.logging.Log;

import com.ailk.cuc.autotestbg.common.business.interf.AssemblyComponentInterface;
import com.ailk.cuc.autotestbg.common.constants.StaticParam;
import com.ailk.cuc.autotestbg.common.exception.DataBaseException;
import com.ailk.cuc.autotestbg.common.exception.IOForFileException;
import com.ailk.cuc.autotestbg.common.utils.DbUtils;
import com.ailk.cuc.autotestbg.common.utils.FileUtils;
import com.ailk.cuc.autotestbg.common.utils.LogUtils;
import com.ailk.cuc.autotestbg.common.utils.SpringContextUtil;
import com.ailk.cuc.autotestbg.xml.bean.AutoEssDataBean;
import com.ailk.cuc.autotestbg.xml.bean.AutoEssTagBean;
import com.ailk.cuc.autotestbg.xml.exception.EcsAssemblyException;
import com.ailk.cuc.autotestbg.xml.utils.EssEcsUtils;
import com.ibatis.sqlmap.client.SqlMapClient;

public class EcsAssemblyComponentImpl implements AssemblyComponentInterface {

	private static Log logger = LogUtils.getLogger(EcsAssemblyComponentImpl.class.getName());
	
	public void assemblyInfo(Map<String, Object> argMapIn,Map<String, Object> argMapOut) throws EcsAssemblyException {
		
		try {
			AutoEssDataBean ecsDataBean = (AutoEssDataBean)argMapIn.get("ecsDataBean");
			logger.info("dataId : "+ecsDataBean.getDataId()+"   interfaceId : "+ecsDataBean.getInterfaceId());
			
			SqlMapClient sqlMapClient = (SqlMapClient)SpringContextUtil.getBean("sqlMapClient");
			
			logger.info("ECS开始组装报文");
			String ecsMessageXml = getEcsMessageForXml(ecsDataBean,sqlMapClient);
			logger.info("ECS组装完成的报文：\r\n"+ecsMessageXml);
			
			argMapIn.put(ecsDataBean.getInterfaceId()+"_request_"+"ecsMessageXml", ecsMessageXml);
		} catch (Exception e) {
			logger.error("ECS组装报文发生异常");
			logger.error(e.getMessage());
			throw new EcsAssemblyException("组装报文时发生数据库操作异常");
		}
	}
	
	/**
	 * 组装ESS报文
	 * 
	 * @param autoEssData
	 * @return
	 * @throws DataBaseException 
	 * @throws IOForFileException 
	 */
	@SuppressWarnings("unchecked")
	private String getEcsMessageForXml(AutoEssDataBean essDataBean,SqlMapClient sqlMapClient) throws DataBaseException, IOForFileException {
		String xml = null;
		String xmlHead = null;
		String xmlHeadPath = null;
		// 初始化buff，在读取完报文体后，再补充上剩余部分。
		StringBuilder buff = new StringBuilder();
		Map<String, Object> map = new HashMap<String, Object>();
		Pattern pattern = Pattern.compile(".+SQL\\{.+", Pattern.CASE_INSENSITIVE);

		// 第一步：读取报文头
		// 
		xmlHeadPath = StaticParam.xmlHeadPath + essDataBean.getInterfaceId() + "HEAD.txt";

		xmlHead = readFileByLines(xmlHeadPath);
		
		
		// 第二步 读取报文体（CDATA包括的内容）
		try {
			AutoEssTagBean tagroot = (AutoEssTagBean)sqlMapClient.queryForObject("xml_ess_ecs_assembly.getRootEssTagBean", essDataBean);
			List<AutoEssTagBean> tagList = (List<AutoEssTagBean>)sqlMapClient.queryForList("xml_ess_ecs_assembly.getRootTagChildren", essDataBean); 
			getCatalogForTag(tagList, tagroot, buff, map, pattern);
		} catch (SQLException e) {
			logger.error("EcsAssemblyComponentImpl.getEcsMessageForXml方法异常");
			throw new DataBaseException("组装ESS报文时，读取数据库发生异常");
		}

		// 替换内容 组装成完整的报文
		xml = xmlHead.replaceFirst("v_essxmlbody", buff.toString()).replaceAll("v_EssTransId", EssEcsUtils.getEssTransId());

		return xml;
	}
	
	/**
	 * 获取场景的所有tag，并按结构组装(老方法(getZongbuChild)还不存在并未废除，此方法是基于字符串组装的)
	 * 
	 * @param tagList
	 * @param headroot
	 * @param buff
	 * @param map
	 * @param pattern
	 * @throws DataBaseException 
	 */
	private static void getCatalogForTag(List<AutoEssTagBean> tagList, AutoEssTagBean headroot, StringBuilder buff, Map<String, Object> map, Pattern pattern) throws DataBaseException {
		if (map.get(headroot.getId()+headroot.getTagValue().trim()) == null) {
			buff.append("<" + headroot.getTagValue() + ">");
			map.put(headroot.getId()+headroot.getTagValue().trim(), headroot.getTagValue());
		}
		for (AutoEssTagBean tag : tagList) {
			if (map.get(tag.getId()+tag.getTagValue().trim()) == null) {
				if (tag.getFatherId() == headroot.getId()) {
					getCatalogForTag(tagList, tag, buff, map, pattern);
				}
			}
		}
		// 0:非叶子节点 1：叶子节点
		if (headroot.getIsLeaf() == 0) {
			buff.append("</" + headroot.getTagValue() + ">");
		} else if (headroot.getIsLeaf() == 1) {
			String tagValue = null;
			if (headroot.getValue() == null) {
				tagValue = "";
			} else {
				// 解析sql语句
				tagValue = replaceSql(headroot.getValue(), pattern);
			}
			buff.append(tagValue);
			buff.append("</" + headroot.getTagValue() + ">");
		}
	}

	/**
	 * 解析请求报文中的sql
	 * 
	 * @param tagValue
	 * @param pattern
	 * @return
	 * @throws DataBaseException 
	 */
	private static String replaceSql(String tagValue, Pattern pattern) throws DataBaseException {
		Matcher matcher = pattern.matcher(tagValue);
		if (matcher.matches()) {

			int dbInstanceStart = tagValue.indexOf("#");
			int dbInstanceEnd = tagValue.indexOf("#", dbInstanceStart + 1);
			String ecsDBInstance = tagValue.substring(dbInstanceStart + 1, dbInstanceEnd);
			String sqlScript = tagValue.substring(dbInstanceEnd + 1);
			String[] sqlArray = sqlScript.split("\\*\\*");
			Map<String, String> paramMap = new HashMap<String, String>();
			int sqlCount = sqlArray.length;
			String sqlResult = null;
			for (int i = 0; i < sqlCount; i++) {
				String singleSql = sqlArray[i];
				String sql = null;
				String paramValue = null;
				int paramPosition = singleSql.indexOf("PARAM{");
				if (paramPosition != -1) {
					sql = singleSql.substring(singleSql.indexOf("{") + 1, paramPosition - 1);
					paramValue = singleSql.substring(singleSql.indexOf("{", paramPosition) + 1, singleSql.indexOf("}", paramPosition));
				} else {
					sql = singleSql.substring(singleSql.indexOf("{") + 1, singleSql.indexOf("}"));
					paramValue = "";
				}
				executeSql(sql, paramValue, i, sqlCount, paramMap, ecsDBInstance);
			}
			sqlResult = paramMap.get("autoTestSqlResult");
			if (sqlResult == null) {
				sqlResult = "";
			}
			paramMap = null;
			return sqlResult;

		} else {
			return tagValue;
		}
	}

	private static void executeSql(String sql, String param, int position, int sqlCount, Map<String, String> paramMap, String ecsDBInstance) throws DataBaseException {
		String[] paramArray = param.split(",");

		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;

		try {
			if (!"".equals(param) && paramArray.length != 0) {
				for (String paramName : paramArray) {
					sql = sql.replaceAll(paramName.trim(), paramMap.get(paramName.substring(1).trim().toUpperCase()));
				}
			}
			conn = DbUtils.getConnection(ecsDBInstance);
			pstmt = conn.prepareStatement(sql);
			rs = pstmt.executeQuery();
			ResultSetMetaData restMetaData = rs.getMetaData();
			int countColumn = restMetaData.getColumnCount();
			String columnName = null;
			String columnValue = null;
			while (rs.next()) {
				for (int i = 1; i <= countColumn; i++) {
					columnName = restMetaData.getColumnName(i);
					columnValue = rs.getString(columnName);
					paramMap.put(columnName, columnValue);
					logger.info(columnName + ":" + columnValue);
				}
			}
			if (position == sqlCount - 1) {
				paramMap.put("autoTestSqlResult", columnValue);
			}

			DbUtils.close(rs, pstmt, null);

		} catch (SQLException e) {
			logger.error("EssAssemblyComponentImpl.executeSql方法异常");
			logger.error(e.getMessage());
			throw new DataBaseException("执行sql语句发生异常");
		}
	}
	
	/**
	 * 读取报文的头文件
	 * 
	 * @param fileName
	 * @return
	 * @throws IOForFileException 
	 */
	private static String readFileByLines(String fileName) throws IOForFileException {
		File file = new File(fileName);
		String result = "";
		try {
			result = FileUtils.readFileToString(file);
		} catch (IOException e) {
			logger.error("读取文件 "+fileName+" 发生异常");
			logger.error(e.getMessage());
			throw new IOForFileException("读取文件 "+fileName+" 发生异常");
		} 
		return result;

	}

}
